package com.gitee.cui.basic.innerlock;

import java.util.concurrent.CountDownLatch;

import com.gitee.cui.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.openjdk.jol.vm.VM;

/**
 * 内置锁结构测试类
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/11/19 16:09
 **/
@Slf4j
public class InnerLockTest {

    private static final int MAX_THREAD = 10;

    private static final int MAX_TURN = 1000;

    /**
     * 展示锁对象结构
     */
    @Test
    public void showNoLockObject() {
        // 输出JVM的信息
        log.info(VM.current().details());
        // 创建一个对象
        ObjectLock objectLock = new ObjectLock();
        log.info("object status: ");
        // 输出对象的布局信息
        objectLock.printSelf();
    }

    /**
     * 偏向锁演示程序示例
     * @throws InterruptedException
     */
    @Test
    public void showBiasedLock() throws InterruptedException {
        log.info(VM.current().details());
        ThreadUtil.sleepMilliSeconds(5000);

        ObjectLock lock = new ObjectLock();
        log.info("抢占锁前，lock的状态：");
        lock.printObjectStruct();
        ThreadUtil.sleepMilliSeconds(5000);

        CountDownLatch count = new CountDownLatch(1);
        Runnable runnable = () -> {
            for (int i = 0; i < MAX_TURN; i++) {
                synchronized (lock) {
                    lock.increase();
                    if (i == MAX_TURN / 2) {
                        log.info("占有锁，lock的状态：");
                        lock.printObjectStruct();
                    }
                }
                ThreadUtil.sleepMilliSeconds(10);
            }
            count.countDown();
        };

        new Thread(runnable, "biased-demo-thread").start();
        count.await();
        ThreadUtil.sleepMilliSeconds(5000);
        log.info("释放锁后，lock的状态：");
        lock.printObjectStruct();
    }

    /**
     * 轻量级锁演示示例
     * @throws InterruptedException
     */
    @Test
    public void showLightWeightLock() throws InterruptedException {
        log.info(VM.current().details());
        ThreadUtil.sleepMilliSeconds(5000);

        ObjectLock lock = new ObjectLock();
        log.info("抢占锁前，lock的状态：");
        lock.printObjectStruct();
        ThreadUtil.sleepMilliSeconds(5000);

        CountDownLatch count = new CountDownLatch(2);
        Runnable runnable = () -> {
            for (int i = 0; i < MAX_TURN; i++) {
                synchronized (lock) {
                    lock.increase();
                    if (i == 1) {
                        log.info("第一个线程占有锁，lock的状态：");
                        lock.printObjectStruct();
                    }
                }
            }
            count.countDown();
            while (true) {
                ThreadUtil.sleepMilliSeconds(1);
            }
        };

        new Thread(runnable).start();
        ThreadUtil.sleepMilliSeconds(1000);

        Runnable lightRunnable = () -> {
            for (int i = 0; i < MAX_TURN; i++) {
                synchronized (lock) {
                    lock.increase();
                    if (i == MAX_TURN / 2) {
                        log.info("第二个线程占有锁，lock的状态：");
                        lock.printObjectStruct();
                    }
                }
                ThreadUtil.sleepMilliSeconds(1);
            }
            count.countDown();
        };

        new Thread(lightRunnable).start();
        count.await();
        ThreadUtil.sleepMilliSeconds(2000);
        log.info("释放锁后，lock的状态：");
        lock.printObjectStruct();
    }

    /**
     * 重量级锁演示示例
     * @throws InterruptedException
     */
    @Test
    public void showHeavyWeightLock() throws InterruptedException {
        log.info(VM.current().details());
        ThreadUtil.sleepMilliSeconds(5000);

        ObjectLock lock = new ObjectLock();
        log.info("抢占锁前，lock的状态：");
        lock.printObjectStruct();
        ThreadUtil.sleepMilliSeconds(5000);

        CountDownLatch count = new CountDownLatch(2);
        Runnable runnable = () -> {
            for (int i = 0; i < MAX_TURN; i++) {
                synchronized (lock) {
                    lock.increase();
                    if (i == 0) {
                        log.info("第一个线程占有锁，lock的状态：");
                        lock.printObjectStruct();
                    }
                }
            }
            count.countDown();
            while (true) {
                ThreadUtil.sleepMilliSeconds(1);
            }
        };

        new Thread(runnable).start();
        ThreadUtil.sleepMilliSeconds(1000);

        Runnable lightRunnable = () -> {
            for (int i = 0; i < MAX_TURN; i++) {
                synchronized (lock) {
                    lock.increase();
                    if (i == 0) {
                        log.info("占有锁，lock的状态：");
                        lock.printObjectStruct();
                    }
                    ThreadUtil.sleepMilliSeconds(1);
                }
            }
            count.countDown();
        };

        new Thread(lightRunnable, "抢锁线程1").start();
        ThreadUtil.sleepMilliSeconds(100);
        new Thread(lightRunnable, "抢锁线程2").start();
        count.await();
        ThreadUtil.sleepMilliSeconds(2000);
        log.info("释放锁后，lock的状态：");
        lock.printObjectStruct();
    }
}
